﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using RemoteControlModel;
using System.Runtime.Serialization.Formatters.Binary;
using Intorise.Common;
using Intorise.Net;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using System.Windows.Forms;
using Model;
using System.Drawing;
using System.Configuration;

namespace MuBot
{
    public partial class MainWindow
    {
        private static TcpClient client = null;
        private static NetTools net = new NetTools();
        private static string managerHost = "";
        private static int managerHostPort = 520;
        protected static int needLevel = 160;

        public void InitRemoteControl()
        {
            managerHost = ConfigurationManager.AppSettings["MANAGER_HOST"];
            if (string.IsNullOrEmpty(managerHost))
            {
                managerHost = "211.149.184.200";
            }
            managerHost = ConfigurationManager.AppSettings["MANAGER_HOST"];
            if (!int.TryParse(ConfigurationManager.AppSettings["MANAGER_HOST_PORT"], out managerHostPort))
            {
                managerHostPort = 520;
            }
            Register();
        }

        private void Register()
        {
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    try
                    {
                        client = new TcpClient(managerHost, managerHostPort);
                        var stream = client.GetStream();
                        var message = new RegisterMessage
                        {
                            ClientName = AppDomain.CurrentDomain.BaseDirectory,
                            Type = BotClientType.升级程序,
                            Version = BasicTools.GetAssemblyFileVersion()
                        };
                        var data = message.Serialize();
                        stream.Write(data, 0, data.Length);
                    }
                    catch (Exception ex)
                    {
                        ConsoleBLL.WriteLineError(ex.Message);
                    }
                    if (client != null && client.Connected)
                    {
                        ConsoleBLL.WriteLineInfo("管理服务器连接成功！");
                        break;
                    }
                    else
                    {
                        ConsoleBLL.WriteLineWaring("无法连接管理服务器，30秒后再次尝试！");
                        Thread.Sleep(1000 * 30);
                    }
                }

                ProcessMessage();
            });
        }

        private void ProcessMessage()
        {
            ConsoleBLL.WriteLineInfo("开始等待管理服务器消息...");
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    if (!NetTools.IsConnected(client))
                    {
                        client.Close();
                        ConsoleBLL.WriteLineWaring("与管理服务器的连接已断开，重新连接...");
                        Register(); break;
                    }
                    try
                    {
                        var msg = RemoteControlModel.Message.ReadMessage(client.GetStream());
                        if (msg == null)
                        {
                            Thread.Sleep(1000);
                            continue;
                        }
                        ConsoleBLL.WriteLineInfo("收到管理服务器消息：" + msg.MessageType);
                        switch (msg.MessageType)
                        {
                            case RemoteControlModel.ManagerMessageTypeEnum.Reboot:
                                Reboot();
                                break;
                            case RemoteControlModel.ManagerMessageTypeEnum.RunBot:
                                AccountDispatched((RunBotMessage)msg);
                                break;
                            case ManagerMessageTypeEnum.UpdateClient:
                                UpdateClient((UpdateClientMessage)msg);
                                break;
                            case ManagerMessageTypeEnum.Report:
                                Report((ReportMessage)msg);
                                break;
                            case ManagerMessageTypeEnum.StopServer:
                                StopServer((StopServerMessage)msg);
                                break;
                            case ManagerMessageTypeEnum.ServerTask:
                                ServerTask((ServerTaskMessage)msg);
                                break;
                        }
                    }
                    catch (Exception ex)
                    {
                        ConsoleBLL.WriteLineError(ex.Message);
                    }
                }
            });
        }

        private static RemoteControlModel.Message ReadMessage(NetworkStream stream)
        {
            byte[] buffer = new byte[4];
            int length = stream.Read(buffer, 0, 4);//读取4个字节为接下来的数据包的长度
            if (length < 4)
            {
                ConsoleBLL.WriteLineWaring("length < 4：" + length);
                return null;
            }

            var packgetLength = net.GetHostInt32(buffer, 0);
            ConsoleBLL.WriteLineInfo("packgetLength:" + packgetLength);
            buffer = new byte[packgetLength];

            length = 0;
            int needReadLength = packgetLength;
            do
            {
                length = stream.Read(buffer, length, needReadLength);
                if (length == needReadLength) { break; }
                needReadLength = needReadLength - length;
            } while (true);

            RemoteControlModel.Message message = null;
            BinaryFormatter formater = new BinaryFormatter();

            try
            {
                using (MemoryStream memory = new MemoryStream(buffer, 0, packgetLength))
                {
                    message = (RemoteControlModel.Message)formater.Deserialize(memory);
                }
            }
            catch (Exception ex)
            {
                ConsoleBLL.WriteLineError(ex.Message);
            }

            if (message == null)
            {
                ConsoleBLL.WriteLineError("反序列化Message失败！");
            }
            return message;
        }

        private static void WriteMessage(RemoteControlModel.Message msg)
        {
            try
            {
                var data = msg.Serialize();
                var stream = client.GetStream();
                stream.Write(data, 0, data.Length);
                stream.Flush();
            }
            catch (Exception ex)
            {
                ConsoleBLL.WriteLineError("Send MSG to server error:" + ex.Message);
            }
        }

        /// <summary>
        /// 根据Player对象创建Character对象
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        private Character GetCharacter(Player x)
        {
            Character character = new Character();
            character.PID = x.ID;
            character.LastLoginTime = DateTime.Now;
            character.Level = x.Level;
            character.Line = x.CurrentLine;
            //character.Location = x.Location;
            character.MapName = x.CurrentMap == null ? "" : x.CurrentMap.Name;
            character.Name = x.Name;
            character.AccountItem = new RemoteControlModel.Account { Username = x.AccountName, Password = x.PlayerAccount.Password };
            character.ServerNo = x.ServerID;
            character.WarehouseInfo = x.ItemInfo;
            character.PlayerStatus = (CharacterStatusEnum)(int)x.Status;
            return character;
        }

        /// <summary>
        /// 删除账号并更新表格
        /// </summary>
        private void RemoveAndUpdateGrid(params Player[] removes)
        {
            lock (players)
            {
                removes.ToList().ForEach(x =>
                {
                    players.Remove(x);
                });
            }
            UpdateGrid();
        }

        /// <summary>
        /// 增加账号并更新表格
        /// </summary>
        private void AddAndUpdateGrid(params Player[] adds)
        {
            lock (players)
            {
                adds.ToList().ForEach(x =>
                {
                    players.Add(x);
                });
            }
            UpdateGrid();
        }

        private void UpdateGrid()
        {
            if (this.dataGridView1.InvokeRequired)
            {
                this.dataGridView1.Invoke(new Action(() =>
                {
                    lock (players)
                    {
                        this.playerBindingSource.DataSource = null;
                        this.playerBindingSource.DataSource = players;
                        this.dataGridView1.Update();
                    }
                }));
            }
            else
            {
                lock (players)
                {
                    this.playerBindingSource.DataSource = null;
                    this.playerBindingSource.DataSource = players;
                    this.dataGridView1.Update();
                }
            }
        }

        #region 消息处理
        private static void Reboot()
        {
            ConsoleBLL.WriteLineWaring("重新启动程序...");
            Process p = new Process();
            p.StartInfo = new ProcessStartInfo(Application.ExecutablePath);
            p.StartInfo.WorkingDirectory = Application.StartupPath;
            //p.StartInfo.Arguments = "/a ";
            p.Start();
            Application.Exit();
        }

        private void AccountDispatched(RemoteControlModel.RunBotMessage msg)
        {
            ConsoleBLL.WriteLineWaring("收到服务器分配的账号数据...");
            needLevel = msg.NeedLevel;
            Random r = new Random();
            List<Character> list = new List<Character>();
            List<Player> adds = new List<Player>();

            var resultMsg = new RunBotResultMessage();
            lock (players)
            {
                msg.Characters.ForEach(f =>
                {
                    resultMsg.Result.Add(f.ID.Value, false);
                    if (players.Count(c => c.ServerID == f.ServerNo) + adds.Count(c => c.ServerID == f.ServerNo) > 9)//每个服务器最多分配10个账号
                    {
                        ConsoleBLL.WriteLineWaring(f.ServerNo + " 已经有10个账号在运行");
                        return;
                    }

                    if (players.Count(c => c.ServerID == f.ServerNo && c.AccountName == f.AccountItem.Username) > 0)
                    {
                        ConsoleBLL.WriteLineWaring(f.ServerNo + " " + f.AccountItem.Username + " 已经在队列中");
                        return;
                    }
                    resultMsg.Result[f.ID.Value] = true;
                    var account = new Model.Account { Username = f.AccountItem.Username, Password = f.AccountItem.Password, ServerID = f.ServerNo };
                    Player p = new Player(account, config);
                    p.Master = new Warehouse { ID = f.WarehouseID, Location = new Point(410, 132), Line = 1, CurrentMap = Maps.GetMap("地下城二层") };//仓库号的编号和停放地图地址
                    p.CurrentLine = r.Next(3) + 1;
                    adds.Add(p);
                    f.PlayerStatus = CharacterStatusEnum.等待;
                    list.Add(f);
                    ConsoleBLL.WriteLineInfo(p.ServerID + "\t" + p.PlayerAccount.Username + "\t" + p.PlayerAccount.Password + "\t" + p.CurrentLine + "\t" + p.Master.ID);
                });
            }

            ConsoleBLL.WriteLineInfo("Send RunBotResultMessage");
            WriteMessage(resultMsg);//发送账号分配结果
            AddAndUpdateGrid(adds.ToArray());

            if (this.btnStartAll.Enabled)
            {
                btnStartAll_Click(null, null);
            }
        }

        private void UpdateClient(UpdateClientMessage msg)
        {
            Process p = new Process();
            p.StartInfo = new ProcessStartInfo(AppDomain.CurrentDomain.BaseDirectory + "Update.exe", msg.Filename);
            p.Start();
            Application.Exit();
        }

        private void Report(ReportMessage reportMessage)
        {
            var msg = new ReportMessage();
            msg.Characters = new List<Character>();
            msg.ReportText = "";
            lock (players)
            {
                players.ForEach(x =>
                {
                    msg.Characters.Add(GetCharacter(x));
                });
            }

            ConsoleBLL.WriteLineInfo("Send ReportMessage");
            WriteMessage(msg);
        }

        private void StopServer(StopServerMessage msg)
        {
            this.dataGridView1.SuspendLayout();
            List<Player> list = new List<Player>();
            lock (players)
            {
                msg.ServerNoList.ForEach(s =>
                {
                    lock (players)
                    {
                        var items = players.Where(f => f.ServerID == s).ToList();
                        items.ForEach(x =>
                        {
                            //如果不是已完成，则改为停止
                            GameHelper.RunThread((obj) =>
                            {
                                Player p = (Player)obj;
                                p.Quit(p.Status != PlayerStatusEnum.任务完成 ? PlayerStatusEnum.停止 : p.Status);
                            }, x);
                            list.Add(x);
                        });
                    }
                });
            }

            RemoveAndUpdateGrid(list.ToArray());

            var report = new ReportMessage();
            report.Characters = new List<Character>();
            list.ForEach(x =>
            {
                report.Characters.Add(GetCharacter(x));
            });

            ConsoleBLL.WriteLineInfo("Send ReportMessage");
            WriteMessage(report);//报告挂机号数据
            ConsoleBLL.WriteLineInfo("Send StopServerMessage");
            WriteMessage(msg);//报告停止服务器成功
        }

        private void ServerTask(ServerTaskMessage msg)
        {
            ConsoleBLL.WriteLineInfo("开始处理ServerTaskMessage");
            Random r = new Random();
            lock (players)
            {
                msg.Servers.ForEach(s =>
                {
                    if (s.IsRunning)
                    {
                        if (players.Count(c => c.ServerID == s.ServerNo) > 0)
                        {
                            ConsoleBLL.WriteLineWaring(s.Name + " 已经在挂机中，跳过");
                            return;
                        }
                        List<Player> adds = new List<Player>();
                        accounts.ForEach(x =>
                        {
                            if (adds.Count == 10)
                            {
                                ConsoleBLL.WriteLineWaring(s.Name + " 已经有10个账号在挂机，跳过账号：" + x); return;
                            }
                            Player p = new Player(new Model.Account(), config);
                            p.AccountName = x.Username;
                            p.PlayerAccount.Username = x.Username;
                            p.PlayerAccount.Password = x.Password;
                            p.ServerID = s.ServerNo;
                            p.PlayerAccount.ServerID = s.ServerNo;
                            p.CurrentLine = r.Next(3) + 1;
                            p.Master = new Warehouse { ID = s.WarehouseID, Location = new Point(410, 132), Line = 1, CurrentMap = Maps.GetMap("地下城二层") };//仓库号的编号和停放地图地址
                            adds.Add(p);
                        });
                        players.AddRange(adds);
                        ConsoleBLL.WriteLineInfo(s.Name + " 开始挂机");
                    }
                    else
                    {
                        var runningPlayers = players.Where(w => w.ServerID == s.ServerNo).ToList();
                        runningPlayers.ForEach(x =>
                        {
                            x.Quit(PlayerStatusEnum.停止);
                            players.Remove(x);
                        });
                        ConsoleBLL.WriteLineInfo(s.Name + " 停止挂机");
                    }
                });
            }
            if (btnStartAll.Enabled)
            {
                btnStartAll_Click(null, null);
            }
        }
        #endregion
    }
}
